home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / smtpserv.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  17KB  |  806 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <time.h>
  6. #ifdef __TURBOC__
  7. #include <fcntl.h>
  8. #endif
  9. #ifdef UNIX
  10. #include <sys/types.h>
  11. #include <memory.h>
  12. #include <string.h>
  13. #endif
  14. #include <ctype.h>
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "netuser.h"
  18. #include "timer.h"
  19. #include "tcp.h"
  20. #include "smtp.h"
  21.  
  22. #ifdef    UNIX
  23. #undef    toupper
  24. #undef    tolower
  25. time_t time();
  26. #endif
  27. #ifdef    BSD
  28. char *sprintf();
  29. #endif
  30. char *getname();
  31. void mail_delete();
  32. static int rqueuejob();
  33. int queuejob();
  34. int validate_address();
  35. long get_msgid();
  36. struct list *addlist();
  37. struct list * expandalias();
  38.  
  39. /* Command table */
  40. static char *commands[] = {
  41.     "helo",
  42. #define    HELO_CMD    0
  43.     "noop",
  44. #define    NOOP_CMD    1
  45.     "mail from:",
  46. #define    MAIL_CMD    2
  47.     "quit",
  48. #define    QUIT_CMD    3
  49.     "rcpt to:",
  50. #define    RCPT_CMD    4
  51.     "help",
  52. #define    HELP_CMD    5
  53.     "data",
  54. #define    DATA_CMD    6
  55.     "rset",
  56. #define    RSET_CMD    7
  57.     NULLCHAR
  58. };
  59.  
  60. /* Reply messages */
  61. static char help[] = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  62. static char banner[] = "220 %s SMTP ready\r\n";
  63. static char closing[] = "221 Closing\r\n";
  64. static char ok[] = "250 Ok\r\n";
  65. static char reset[] = "250 Reset state\r\n";
  66. static char sent[] = "250 Sent\r\n";
  67. static char ourname[] = "250 %s, Share and Enjoy!\r\n";
  68. static char enter[] = "354 Enter mail, end with .\r\n";
  69. static char ioerr[] = "452 Temp file write error\r\n";
  70. static char mboxerr[] = "452 Mailbox write error\r\n";
  71. static char badcmd[] = "500 Command unrecognized\r\n";
  72. static char syntax[] = "501 Syntax error\r\n";
  73. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  74. static char unknown[] = "550 <%s> address unknown\r\n";
  75.  
  76. static struct tcb *smtp_tcb;
  77. /* Start up SMTP receiver service */
  78. smtp1(argc,argv)
  79. int argc;
  80. char *argv[];
  81. {
  82.     struct socket lsocket;
  83.     void r_mail(),s_mail();
  84.  
  85.     lsocket.address = ip_addr;
  86.     if(argc < 2)
  87.         lsocket.port = SMTP_PORT;
  88.     else
  89.         lsocket.port = atoi(argv[1]);
  90.  
  91.     smtp_tcb = open_tcp(&lsocket,NULLSOCK,
  92.         TCP_SERVER,0,r_mail,NULLVFP,s_mail,0,(char *)NULL);
  93. }
  94.  
  95. /* Shutdown SMTP service (existing connections are allowed to finish) */
  96. smtp0()
  97. {
  98.     if(smtp_tcb != NULLTCB)
  99.         close_tcp(smtp_tcb);
  100. }
  101.  
  102. /* SMTP connection state change upcall handler */
  103. /*ARGSUSED*/
  104. static void
  105. s_mail(tcb,old,new)
  106. struct tcb *tcb;
  107. char old,new;
  108. {
  109.     struct mail *mp,*mail_create();
  110.  
  111.     switch(new){
  112. #ifdef    QUICKSTART
  113.     case SYN_RECEIVED:
  114. #else
  115.     case ESTABLISHED:
  116. #endif
  117.         if((mp = mail_create(tcb)) == NULLMAIL){
  118.             close_tcp(tcb);
  119.             break;
  120.         }
  121.         (void) tprintf(mp->tcb,banner,hostname);
  122.         log(tcb,"open SMTP");
  123.         break;        
  124.     case CLOSE_WAIT:
  125.         close_tcp(tcb);
  126.         break;
  127.     case CLOSED:
  128.         log(tcb,"close SMTP");
  129.         mp = (struct mail *)tcb->user;
  130.         mail_delete(mp);                
  131.         del_tcp(tcb);
  132.         /* Check if server is being shut down */
  133.         if(tcb == smtp_tcb)
  134.             smtp_tcb = NULLTCB;
  135.         break;
  136.     }
  137. }
  138.  
  139. /* SMTP receiver upcall handler */
  140. static void
  141. r_mail(tcb,cnt)
  142. struct tcb *tcb;
  143. int16 cnt;
  144. {
  145.     register struct mail *mp;
  146.     char c;
  147.     struct mbuf *bp;
  148.     char *inet_ntoa();
  149.     void docommand(),doline();
  150.  
  151.     if((mp = (struct mail *)tcb->user) == NULLMAIL){
  152.         /* Unknown session */
  153.         close_tcp(tcb);
  154.         return;
  155.     }
  156.     recv_tcp(tcb,&bp,cnt);
  157.     /* Assemble an input line in the session buffer.
  158.      * Return if incomplete
  159.      */
  160.     while(pullup(&bp,&c,1) == 1){
  161.         switch(c){
  162.         case '\r':    /* Strip cr's */
  163. #ifdef MSDOS
  164.         case '\032':    /* Strip ctrl/Z's */
  165. #endif
  166.             continue;
  167.         case '\n':    /* Complete line; process it */
  168.             mp->buf[mp->cnt] = '\0';
  169.             doline(mp);
  170.             break;
  171.         default:    /* Assemble line */
  172.             if(mp->cnt != LINELEN-1)
  173.                 mp->buf[mp->cnt++] = c;
  174.             break;
  175.         }
  176.     }
  177. }
  178. /* Process a line read on an SMTP connection (any state) */
  179. static void
  180. doline(mp)
  181. register struct mail *mp;
  182. {
  183.     void docommand(),deliver();
  184.  
  185.     switch(mp->state){
  186.     case COMMAND_STATE:
  187.         docommand(mp);
  188.         break;
  189.     case DATA_STATE:
  190.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  191.         if(mp->buf[0] == '.' && mp->buf[1] == '\0'){
  192.             mp->state = COMMAND_STATE;
  193.         /* Also sends appropriate response */
  194.             deliver(mp);
  195.             fclose(mp->data);
  196.             mp->data = NULLFILE;
  197.             del_list(mp->to);
  198.             mp->to = NULLLIST;
  199.             break;
  200.         }
  201.         /* for UNIX mail compatiblity */
  202.         if (strncmp(mp->buf,"From ",5) == 0)
  203.             (void) putc('>',mp->data);
  204.         /* Append to data file */
  205.         if(fprintf(mp->data,"%s\n",mp->buf) < 0){
  206.             mp->state = COMMAND_STATE;
  207.             (void) tprintf(mp->tcb,ioerr);
  208.         }
  209.         break;
  210.     }
  211.     mp->cnt = 0;
  212. }
  213. /* Create control block, initialize */
  214. static struct mail *
  215. mail_create(tcb)
  216. register struct tcb *tcb;
  217. {
  218.     register struct mail *mp;
  219.  
  220.     if((mp = (struct mail *)calloc(1,sizeof (struct mail))) == NULLMAIL)
  221.         return NULLMAIL;
  222.     mp->tcb = tcb;        /* Downward pointer */
  223.     tcb->user = (char *)mp;    /* Upward pointer */
  224.     return mp;
  225. }
  226.  
  227. /* Free resources, delete control block */
  228. static void
  229. mail_delete(mp)
  230. register struct mail *mp;
  231. {
  232.  
  233.     if (mp == NULLMAIL)
  234.         return;
  235.     if(mp->system != NULLCHAR)
  236.         free(mp->system);
  237.     if(mp->from != NULLCHAR)
  238.         free(mp->from);
  239.     if(mp->data != NULLFILE)
  240.         fclose(mp->data);
  241.     del_list(mp->to);
  242.     free((char *)mp);
  243. }
  244.  
  245. /* Parse and execute mail commands */
  246. static void
  247. docommand(mp)
  248. register struct mail *mp;
  249. {
  250.     register char **cmdp,*arg,*cp,*cmd;
  251.     FILE *tmpfile();
  252.     long t;
  253.     char address_type;
  254.  
  255.     cmd = mp->buf;
  256.     if(mp->cnt < 4){
  257.         /* Can't be a legal SMTP command */
  258.         (void) tprintf(mp->tcb,badcmd);
  259.         return;
  260.     }    
  261.     cmd = mp->buf;
  262.  
  263.     /* Translate entire buffer to lower case */
  264.     for(cp = cmd;*cp != '\0';cp++)
  265.         *cp = tolower(*cp);
  266.  
  267.     /* Find command in table; if not present, return syntax error */
  268.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  269.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  270.             break;
  271.     if(*cmdp == NULLCHAR){
  272.         (void) tprintf(mp->tcb,badcmd);
  273.         return;
  274.     }
  275.     arg = &cmd[strlen(*cmdp)];
  276.     /* Skip spaces after command */
  277.     while(*arg == ' ')
  278.         arg++;
  279.     /* Execute specific command */
  280.     switch(cmdp-commands){
  281.     case HELO_CMD:
  282.         if(mp->system != NULLCHAR)
  283.             free(mp->system);
  284.         if((mp->system = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  285.             /* If the system is out of memory, just close */
  286.             close_tcp(mp->tcb);
  287.             break;            
  288.         } else {
  289.             strcpy(mp->system,arg);
  290.             (void) tprintf(mp->tcb,ourname,hostname);
  291.         }
  292.         break;
  293.     case NOOP_CMD:
  294.         (void) tprintf(mp->tcb,ok);
  295.         break;
  296.     case MAIL_CMD:
  297.         if(mp->from != NULLCHAR)
  298.             free(mp->from);
  299.         if((mp->from = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  300.             /* If the system is out of memory, just close */
  301.             close_tcp(mp->tcb);
  302.             break;            
  303.         } else {
  304.             if((cp = getname(arg)) == NULLCHAR){
  305.                 (void) tprintf(mp->tcb,syntax);
  306.                 break;
  307.             }
  308.             strcpy(mp->from,cp);
  309.             (void) tprintf(mp->tcb,ok);
  310.         }
  311.         break;
  312.     case QUIT_CMD:
  313.         (void) tprintf(mp->tcb,closing);
  314.         close_tcp(mp->tcb);
  315.         break;
  316.     case RCPT_CMD:    /* Specify recipient */
  317.         if((cp = getname(arg)) == NULLCHAR){
  318.             (void) tprintf(mp->tcb,syntax);
  319.             break;
  320.         }
  321.  
  322.         /* check if address is ok */
  323.         if ((address_type = validate_address(cp)) == BADADDR) {
  324.             (void) tprintf(mp->tcb,unknown,cp);
  325.             break;
  326.         }
  327.         /* if a local address check for an alias */
  328.         if (address_type == LOCAL)
  329.             expandalias(&mp->to, cp);
  330.         else
  331.             /* a remote address is added to the list */
  332.             addlist(&mp->to, cp, address_type);
  333.  
  334.         (void) tprintf(mp->tcb,ok);
  335.         break;
  336.     case HELP_CMD:
  337.         (void) tprintf(mp->tcb,help);
  338.         break;
  339.     case DATA_CMD:
  340.         if(mp->to == NULLLIST){
  341.             (void) tprintf(mp->tcb,needrcpt);
  342.             break;
  343.         }
  344.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  345.         if((mp->data = tmpfile()) == NULLFILE){
  346.             (void) tprintf(mp->tcb,ioerr);
  347.             break;
  348.         }
  349.         /* Add timestamp; ptime adds newline */
  350.         time(&t);
  351.         fprintf(mp->data,"Received: ");
  352.         if(mp->system != NULLCHAR)
  353.             fprintf(mp->data,"from %s ",mp->system);
  354.         fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  355.                 hostname, get_msgid(), ptime(&t));
  356.         if(ferror(mp->data)){
  357.             (void) tprintf(mp->tcb,ioerr);
  358.         } else {
  359.             mp->state = DATA_STATE;
  360.             (void) tprintf(mp->tcb,enter);
  361.         }
  362.         break;
  363.     case RSET_CMD:
  364.         del_list(mp->to);
  365.         mp->to = NULLLIST;
  366.         mp->state = COMMAND_STATE;
  367.         (void) tprintf(mp->tcb,reset);
  368.         break;
  369.     }
  370. }
  371. /* Given a string of the form <user@host>, extract the part inside the
  372.  * brackets and return a pointer to it.
  373.  */
  374. static
  375. char *
  376. getname(cp)
  377. register char *cp;
  378. {
  379.     register char *cp1;
  380.  
  381.     if((cp = index(cp,'<')) == NULLCHAR)
  382.         return NULLCHAR;
  383.     cp++;    /* cp -> first char of name */
  384.     if((cp1 = index(cp,'>')) == NULLCHAR)
  385.         return NULLCHAR;
  386.     *cp1 = '\0';
  387.     return cp;
  388. }
  389.  
  390. /* Deliver mail to the appropriate mail boxes and delete temp file */
  391. static
  392. void
  393. deliver(mp)
  394. register struct mail *mp;
  395. {
  396.     int ret;
  397.  
  398.     /* send to the rqueue */
  399.     if ((smtpmode & QUEUE) != 0) {
  400.         ret = router_queue(mp->tcb,mp->data,mp->from,mp->to);
  401.         if (ret != 0)
  402.             (void) tprintf(mp->tcb,ioerr);
  403.     } else {
  404.         ret = mailit(mp->tcb,mp->data,mp->from,mp->to);
  405.         if (ret != 0)
  406.             (void) tprintf(mp->tcb,mboxerr);
  407.     }
  408.     if (ret == 0)
  409.         (void) tprintf(mp->tcb,sent);
  410.         
  411. }
  412.  
  413. /* used to save local mail or reroute remote mail */
  414. mailit(tcb,data,from,to)
  415. struct tcb *tcb;
  416. FILE *data;
  417. char *from;
  418. struct list *to;
  419. {
  420.     register struct list *ap;
  421.     register FILE *fp;
  422.     int c;
  423.     char    mailbox[50];
  424.     char    *cp;
  425.     char    *desthost;
  426.     int    fail = 0;
  427.     time_t    t;
  428.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  429.  
  430.         fseek(data,0L,0);    /* rewind */
  431.  
  432.         /* non local mail queue it */
  433.         if (ap->type == DOMAIN) {
  434.             if ((desthost = index(ap->val,'@')) != NULLCHAR);
  435.                 desthost++;
  436.             fail = queuejob(tcb,data,desthost,ap->val,from);
  437.         } else {
  438.             /* strip off host name */
  439.             if ((cp = index(ap->val,'@')) != NULLCHAR)
  440.                 *cp = '\0';
  441.  
  442.             /* truncate long user names */
  443.             if (strlen(ap->val) > MBOXLEN)
  444.                 ap->val[MBOXLEN] = '\0';
  445.  
  446.             /* if mail file is busy save it in our smtp queue
  447.              * and let the smtp daemon try later.
  448.              */
  449.             if (mlock(mailspool,ap->val))
  450.                 fail = queuejob(tcb,data,hostname,ap->val,from);
  451.             else {
  452.                 sprintf(mailbox,"%s/%s.txt",mailspool,ap->val);
  453.                 if((fp = fopen(mailbox,"a+")) != NULLFILE) {
  454.                     time(&t);
  455.                     fprintf(fp,
  456.                     "From %s %s",from,ctime(&t));
  457.                     while((c = getc(data)) != EOF)
  458.                         if(putc(c,fp) == EOF)
  459.                             break;
  460.                     if(ferror(fp))
  461.                         fail = 1;
  462.                     else
  463.                         fprintf(fp,"\n");
  464.                     /* Leave a blank line between msgs */
  465.                     fclose(fp);
  466.                     printf("New mail arrived for %s\n",ap->val);
  467.                     fflush(stdout);
  468.                 } else 
  469.                     fail = 1;
  470.                 (void) rmlock(mailspool,ap->val);
  471.                 if (fail)
  472.                     break;
  473.                 log(tcb,
  474.                 "SMTP recv: To: %s From: %s",ap->val,from);
  475.             }
  476.         }
  477.     }
  478.     return(fail) ;
  479. }
  480.  
  481. /* Return Date/Time in Arpanet format in passed string */
  482. char *
  483. ptime(t)
  484. long *t;
  485. {
  486.     /* Print out the time and date field as
  487.      *        "DAY day MONTH year hh:mm:ss ZONE"
  488.      */
  489.     register struct tm *ltm;
  490.     static char tz[4];
  491.     static char str[40];
  492.     extern char *getenv();
  493.     extern struct tm *localtime();
  494.     char *p;
  495.     static char *days[7] = {
  496.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  497.  
  498.     static char *months[12] = {
  499.         "Jan","Feb","Mar","Apr","May","Jun",
  500.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  501.  
  502.     /* Read the system time */
  503.     ltm = localtime(t);
  504.  
  505.     if (*tz == '\0')
  506.         if (((p = getenv("TZ")) == NULL) &&
  507.              (p = getenv("TIMEZONE")) == NULL)
  508.             strcpy(tz,"GMT");
  509.         else
  510.             strncpy(tz,p,3);
  511.  
  512.     /* rfc 822 format */
  513.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  514.         days[ltm->tm_wday],
  515.         ltm->tm_mday,
  516.         months[ltm->tm_mon],
  517.         ltm->tm_year,
  518.         ltm->tm_hour,
  519.         ltm->tm_min,
  520.         ltm->tm_sec,
  521.         tz);
  522.     return(str);
  523. }
  524.  
  525. long 
  526. get_msgid()
  527. {
  528.     char sfilename[LINELEN];
  529.     char s[20];
  530.     register long sequence = 0;
  531.     FILE *sfile;
  532.     long atol();
  533.  
  534.     sprintf(sfilename,"%s/sequence.seq",mailqdir);
  535.     sfile = fopen(sfilename,"r");
  536.  
  537.     /* if sequence file exists, get the value, otherwise set it */
  538.     if (sfile != NULL) {
  539.         (void) fgets(s,sizeof(s),sfile);
  540.         sequence = atol(s);
  541.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  542.         if (sequence < 0L || sequence > 99999999L )
  543.             sequence = 0;
  544.         fclose(sfile);
  545.     }
  546.  
  547.     /* increment sequence number, and write to sequence file */
  548.     sfile = fopen(sfilename,"w");
  549.     fprintf(sfile,"%ld",++sequence);
  550.     fclose(sfile);
  551.     return sequence;
  552. }
  553.  
  554. #ifdef    MSDOS
  555. /* Illegal characters in a DOS filename */
  556. static char baddoschars[] = "\"[]:|<>+=;,";
  557. #endif
  558.  
  559. /* test if mail address is valid */
  560. int
  561. validate_address(s)
  562. char *s;
  563. {
  564.     char *cp;
  565.     int32 addr;
  566.     int32 mailroute();
  567.  
  568.  
  569.  
  570.     /* if address has @ in it the check dest address */
  571.     if ((cp = index(s,'@')) != NULLCHAR) {
  572.         cp++;
  573.         /* 1st check if its our hostname
  574.         * if not then check the hosts file and see
  575.         * if we can resolve ther address to a know site
  576.         * or one of our aliases
  577.         */
  578.         if (strcmp(cp,hostname) != 0) {
  579.             if ((addr = mailroute(cp)) == 0
  580.                 && (smtpmode & QUEUE) == 0)
  581.                 return BADADDR;
  582.             if (addr != ip_addr)
  583.                 return DOMAIN;
  584.         }
  585.         
  586.         /* on a local address remove the host name part */
  587.         *--cp = '\0';
  588.     }
  589.  
  590.     /* if using an external router leave address alone */
  591.     if ((smtpmode & QUEUE) != 0)
  592.         return LOCAL;
  593.  
  594.  
  595.     /* check for the user%host hack */
  596.     if ((cp = index(s,'%')) != NULLCHAR) {
  597.         *cp = '@';
  598.         cp++;
  599.         /* reroute based on host name following the % seperator */
  600.         if (mailroute(cp) == 0)
  601.             return BADADDR;
  602.         else
  603.             return DOMAIN;
  604.     }
  605.  
  606. #ifdef MSDOS    /* dos file name checks */
  607.     /* Check for characters illegal in MS-DOS file names */
  608.     for(cp = baddoschars;*cp != '\0';cp++){
  609.         if(index(s,*cp) != NULLCHAR)
  610.             return BADADDR;    
  611.     }
  612. #endif
  613.     return LOCAL;
  614. }
  615.  
  616. /* place a mail job in the outbound queue */
  617. int
  618. queuejob(tcb,dfile,host,to,from)
  619. struct tcb *tcb;
  620. FILE *dfile;
  621. char *host,*to,*from;
  622. {
  623.     FILE *fp;
  624.     char tmpstring[50];
  625.     char prefix[9];
  626.     register int c;
  627.  
  628.     sprintf(prefix,"%ld",get_msgid());
  629.     log(tcb,"SMTP queue job %s To: %s From: %s",prefix,to,from);
  630.     mlock(mailqdir,prefix);
  631.     sprintf(tmpstring,"%s/%s.txt",mailqdir,prefix);
  632.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  633.         (void) rmlock(mailqdir,prefix);
  634.         return 1;
  635.     }
  636.     while((c = getc(dfile)) != EOF)
  637.         if(putc(c,fp) == EOF)
  638.             break;
  639.     if(ferror(fp)){
  640.         fclose(fp);
  641.         (void) rmlock(mailqdir,prefix);
  642.         return 1;
  643.     }
  644.     fclose(fp);
  645.     sprintf(tmpstring,"%s/%s.wrk",mailqdir,prefix);
  646.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  647.         (void) rmlock(mailqdir,prefix);
  648.         return 1;
  649.     }
  650.     fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  651.     fclose(fp);
  652.     (void) rmlock(mailqdir,prefix);
  653.     return 0;
  654. }
  655.  
  656. /* Deliver mail to the appropriate mail boxes */
  657. int
  658. router_queue(tcb,data,from,to)
  659. struct tcb *tcb;
  660. FILE *data;
  661. char *from;
  662. struct list *to;
  663. {
  664.     int c;
  665.     register struct list *ap;
  666.     FILE *fp;
  667.     char tmpstring[50];
  668.     char prefix[9];
  669.  
  670.     sprintf(prefix,"%ld",get_msgid());
  671.     mlock(routeqdir,prefix);
  672.     sprintf(tmpstring,"%s/%s.txt",routeqdir,prefix);
  673.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  674.         (void) rmlock(routeqdir,prefix);
  675.         return 1;
  676.     }
  677.     fseek(data,0L,0);    /* rewind */
  678.     while((c = getc(data)) != EOF)
  679.         if(putc(c,fp) == EOF)
  680.             break;
  681.     if(ferror(fp)){
  682.         fclose(fp);
  683.         (void) rmlock(routeqdir,prefix);
  684.         return 1;
  685.     }
  686.     fclose(fp);
  687.     sprintf(tmpstring,"%s/%s.wrk",routeqdir,prefix);
  688.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  689.         (void) rmlock(routeqdir,prefix);
  690.         return 1;
  691.     }
  692.     fprintf(fp,"From: %s\n",from);
  693.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  694.         fprintf(fp,"To: %s\n",ap->val);
  695.     }
  696.     fclose(fp);
  697.     (void) rmlock(routeqdir,prefix);
  698.     log(tcb,"SMTP rqueue job %s From: %s",prefix,from);
  699.     return 0;
  700. }
  701.  
  702. /* add an element to the front of the list pointed to by head 
  703. ** return NULLLIST if out of memory.
  704. */
  705. struct list *
  706. addlist(head,val,type)
  707. struct list **head;
  708. char *val;
  709. int type;
  710. {
  711.     register struct list *tp;
  712.  
  713.     tp = (struct list *)calloc(1,sizeof(struct list));
  714.     if (tp == NULLLIST)
  715.         return NULLLIST;
  716.  
  717.     tp->next = NULLLIST;
  718.  
  719.     /* allocate storage for the char string */
  720.     if ((tp->val = malloc((unsigned)strlen(val)+1)) == NULLCHAR) {
  721.         (void) free((char *)tp);
  722.         return NULLLIST;
  723.     }
  724.     strcpy(tp->val,val);
  725.     tp->type = type;
  726.  
  727.     /* add entry to front of existing list */
  728.     if (*head == NULLLIST)
  729.         *head = tp;
  730.     else {
  731.         tp->next = *head;
  732.         *head = tp;
  733.     }
  734.     return tp;
  735.  
  736. }
  737.  
  738. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  739. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  740.  
  741. /* check for and alias and expand alias into a address list */
  742. struct list *
  743. expandalias(head, user)
  744. struct list **head;
  745. char *user;
  746. {
  747.     FILE *fp;
  748.     register char *s,*p;
  749.     int inalias;
  750.     struct list *tp;
  751.     char buf[LINELEN];
  752.     
  753.     
  754.         /* no alias file found */
  755.     if ((fp = fopen(alias, "r")) == NULLFILE)
  756.         return addlist(head, user, LOCAL);
  757.  
  758.     inalias = 0;
  759.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  760.         p = buf;
  761.         if ( *p == '#' || *p == '\0')
  762.             continue;
  763.         rip(p);
  764.  
  765.         /* if not in an matching entry skip continuation lines */
  766.         if (!inalias && isspace(*p))
  767.             continue;
  768.  
  769.         /* when processing an active alias check for a continuation */
  770.         if (inalias) {
  771.             if (!isspace(*p)) 
  772.                 break;    /* done */
  773.         } else {
  774.             s = p;
  775.             SKIPWORD(p);
  776.             *p++ = '\0';    /* end the alias name */
  777.             if (strcmp(s,user) != 0)
  778.                 continue;    /* no match go on */
  779.             inalias = 1;
  780.         }
  781.  
  782.         /* process the recipients on the alias line */
  783.         SKIPSPACE(p);
  784.         while(*p != '\0' && *p != '#') {
  785.             s = p;
  786.             SKIPWORD(p);
  787.             if (*p != '\0')
  788.                 *p++ = '\0';
  789.  
  790.             /* find hostname */
  791.             if (index(s,'@') != NULLCHAR)
  792.                 tp = addlist(head,s,DOMAIN);
  793.             else
  794.                 tp = addlist(head,s,LOCAL);
  795.             SKIPSPACE(p);
  796.         }
  797.     }
  798.     (void) fclose(fp);
  799.  
  800.     if (inalias)    /* found and processed and alias. */
  801.         return tp;
  802.  
  803.     /* no alias found treat as a local address */
  804.     return addlist(head, user, LOCAL);
  805. }
  806.